﻿using System.Text;
using System.Xml;
using Newtonsoft.Json;

namespace ForguncyPluginPackageTool;

/// <summary>
/// 前端本地化资源生成器
/// </summary>
public class FrontEndLocalResourceGenerator
{
    /// <summary>
    /// 资源的输出路径
    /// </summary>
    private readonly string _outputDir;

    /// <summary>
    /// 插件信息
    /// </summary>
    private readonly PluginItem _pluginItem;

    /// <summary>
    /// Resx文件夹路径
    /// </summary>
    private readonly string _resxFileFolder;

    /// <summary>
    /// 资源模板
    /// </summary>
    private const string LocaleTemplate =
        @"
(() => {
    if (!Forguncy.Plugin.LocalizationResource) {
        Forguncy.Plugin.LocalizationResource = {}
    }
    if (Forguncy.Plugin.LocalizationResource[`#PLUGIN_GUID#`]) {
        Forguncy.Plugin.LocalizationResource[`#PLUGIN_GUID#`] = {
            ...Forguncy.Plugin.LocalizationResource[`#PLUGIN_GUID#`],
            ...#CONTENT#
        };
    } else {
        Forguncy.Plugin.LocalizationResource[`#PLUGIN_GUID#`] = #CONTENT#;
    }
})();
";

    public bool ShouldGenerate => _pluginItem.frontEndLocalization?.extractFromResourceFile?.enable ?? false;

    public FrontEndLocalResourceGenerator(string projectPath, string tempDir, PluginItem pluginItem)
    {
        _pluginItem = pluginItem;
        _resxFileFolder = Path.Combine(projectPath, "Properties");
        if (ShouldGenerate)
        {
            _outputDir = Path.Combine(tempDir,
                _pluginItem.frontEndLocalization?.extractFromResourceFile?.outputDir ?? "Resources\\locale");
        }
    }

    /// <summary>
    /// 生成
    /// </summary>
    /// <returns></returns>
    public void Generate()
    {
        if (!TryGetResxFilePaths(out var resxFilePaths))
        {
            return;
        }

        EnsureOutputDirExists();

        // 默认的资源字典
        var defaultResourceDict = GetResourceDictByResxFilePath(Path.Combine(_resxFileFolder, "Resources.resx"),
            node => node?.Attributes != null && node.Attributes["frontEndAvailable"]?.Value == "true");

        foreach (var resxFile in resxFilePaths)
        {
            var resultDictionary = defaultResourceDict;

            if (Path.GetFileName(resxFile) != "Resources.resx")
            {
                resultDictionary =
                    GetResourceDictByResxFilePath(resxFile,
                        node => defaultResourceDict.ContainsKey(node!.Attributes!["name"]!.Value));

                foreach (var keyValuePair in defaultResourceDict)
                {
                    // 如果默认资源字典中的键在当前资源字典中不存在，则添加到当前资源字典中
                    resultDictionary.TryAdd(keyValuePair.Key, keyValuePair.Value);
                }
            }

            var languageName = GetLanguageNameByFileName(Path.GetFileName(resxFile));
            var filePath = Path.Combine(_outputDir, languageName + ".js");
            var content = GenerateLocaleFileContent(resultDictionary);
            File.WriteAllText(filePath, content, Encoding.UTF8);
        }
    }

    /// <summary>
    /// 生成资源文件内容
    /// </summary>
    /// <param name="resultDictionary"></param>
    /// <returns></returns>
    private string GenerateLocaleFileContent(Dictionary<string, string> resultDictionary)
    {
        var content = JsonConvert.SerializeObject(resultDictionary);

        return LocaleTemplate
            .Replace("#PLUGIN_GUID#", _pluginItem.guid)
            .Replace("#CONTENT#", content);
    }

    /// <summary>
    /// 确保输出目录存在
    /// </summary>
    private void EnsureOutputDirExists()
    {
        if (!Directory.Exists(_outputDir))
        {
            Directory.CreateDirectory(_outputDir);
        }
    }

    /// <summary>
    /// 尝试获取Resx文件路径数组
    /// </summary>
    /// <param name="resxFilePaths"></param>
    /// <returns></returns>
    private bool TryGetResxFilePaths(out string[] resxFilePaths)
    {
        resxFilePaths = Directory.GetFiles(_resxFileFolder, "*.resx", SearchOption.AllDirectories);
        return resxFilePaths.Length != 0;
    }

    /// <summary>
    /// 根据文件名称获取语言名称
    /// </summary>
    /// <param name="fileName"></param>
    /// <returns></returns>
    private static string GetLanguageNameByFileName(string fileName)
    {
        return fileName switch
        {
            "Resources.resx" => "en",
            "Resources.ja.resx" => "ja",
            "Resources.ko-KR.resx" => "kr",
            "Resources.zh-CN.resx" => "cn",
            _ => null
        };
    }

    // todo dou yao biao zhu

    /// <summary>
    /// 根据文件路径获取资源字典
    /// </summary>
    /// <param name="resxPath"></param>
    /// <param name="shouldGenerate"></param>
    /// <returns></returns>
    private static Dictionary<string, string> GetResourceDictByResxFilePath(string resxPath,
        Func<XmlNode, bool> shouldGenerate)
    {
        var dic = new Dictionary<string, string>();
        var doc = new XmlDocument();
        doc.Load(resxPath);

        var nodes = doc.SelectNodes("//data");
        if (nodes is null || nodes.Count == 0)
        {
            return new Dictionary<string, string>(0);
        }

        nodes.Cast<XmlNode>().ToList().ForEach(node =>
        {
            if (node.Attributes == null || node.Attributes.Count == 0)
            {
                return;
            }

            var name = node.Attributes["name"]?.Value;

            if (string.IsNullOrWhiteSpace(name))
            {
                return;
            }

            if (shouldGenerate(node))
            {
                dic[name] = node.SelectSingleNode("value")?.InnerText ?? string.Empty;
            }
        });
        return dic;
    }
}
